import { spawn, exec } from 'node:child_process'
import { EOL } from 'node:os'
import process from 'node:process'
import config from './config.json' assert { type: 'json' }
import { v4 } from 'uuid'
import fs from 'node:fs'
import path from 'node:path'
import { promisify } from 'node:util'

const execAsync = promisify(exec);

async function checkPort(port) {
    try {
        // 获取占用端口的进程 PID（多个 PID 用换行分隔）
        const { stdout } = await execAsync(`lsof -t -i :${port}`);
        const pids = stdout.split('\n').filter(pid => pid.trim() !== '');
        return pids.length ? pids : null;
    } catch (error) {
        if (error.code === 1) { // 退出码 1 表示无进程占用
            return null;
        }
        throw new Error(`检查端口 ${port} 失败: ${error.message}`);
    }
}

async function killProcess(pids) {
    for (const pid of pids) {
        try {
            await execAsync(`kill -9 ${pid}`);
            console.log(`进程 ${pid} 已终止`);
        } catch (error) {
            console.error(`终止进程 ${pid} 失败: ${error.message}`);
        }
    }
}

async function cleanupPorts(ports) {
    console.log('清理端口占用', ports);
    for (const port of ports) {
        const pids = await checkPort(port);
        if (pids) {
            console.log(`端口 ${port} 被进程 ${pids.join(', ')} 占用`);
            await killProcess(pids);
        } else {
            console.log(`端口 ${port} 未被占用`);
        }
    }
}

async function startServer() {
    // 启动测试 mqtt broker
    const childprocess1 = spawn(process.execPath, ['./broker.js'], {
        stdio: 'inherit'
    })
    childprocess1.on('spawn', () => {
        console.log('启动 MQTT Broker -------------------------------------------')
    })

    // 启动本地 http 服务器
    const childprocess2 = spawn(process.execPath, ['./index.js'], {
        stdio: 'inherit'
    })
    childprocess2.on('spawn', () => {
        console.log('启动 http 服务 ------------------------------------------')
    })

    return {
        childprocess1,
        childprocess2
    }
}


const sleep = (ms) => {
    return new Promise((resolve) => setTimeout(resolve, ms, true))
}

const request = async (...args) => {
    const res = await fetch(...args)
    const json = await res.json()
    return json
}

async function test() {
    console.log('%c测试开始!', 'background: red')
    const { port, hostname, db: { path: dbPath } } = config
    const dbFilepath = path.join(process.cwd(), dbPath)
    const userJsonFilepath = path.join(process.cwd(), './static/user.json')
    if (fs.existsSync(dbFilepath)) {
        fs.unlinkSync(dbFilepath)
    }
    if (fs.existsSync(userJsonFilepath)) {
        fs.unlinkSync(userJsonFilepath)
    }

    const httpServerURL = `http://${hostname}:${port}`

    /** ------------------------ 系统未上线，获取系统信息成功 ----------------------------- */
    let getSystemInfoError
    while (getSystemInfoError !== 0) {
        await sleep(1000)
        const osInfo_2 = await request(`${httpServerURL}/api/v1/rest/system/state`)
        getSystemInfoError = osInfo_2.error
        console.log(EOL)
        console.log('获取系统信息: ', JSON.stringify(osInfo_2))
    }

    /** ------------------------- 注册用户 ------------------------------------------------------- */
    await sleep(1000)
    const user = {
        account: v4(),
        password: v4(),
        email: `${v4()}@gmail.com`,
        age: Math.ceil(Math.random() * 100)
    }
    console.log(`随机生成用户数据: ${JSON.stringify(user, null, 4)}`)
    const registerResp = await request(`${httpServerURL}/api/v1/rest/users/register`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(user)
    })
    console.log(`注册结果: ${JSON.stringify(registerResp, null, 4)}`)

    /** ------------------------------ 查询用户 --------------------------------------------- */
    await sleep(1000)
    const searchUserResp = await request(`${httpServerURL}/api/v1/rest/users/${user.account}`)
    console.log(`查询用户数据: ${JSON.stringify(searchUserResp, null, 4)}`)

    /** -------------------------------- 导出用户数据 -------------------------------------------------------- */
    await sleep(1000)
    const exportResp = await request(`${httpServerURL}/api/v1/rest/users/export`, {
        method: 'POST'
    })
    console.log(`导出用户数据结果: ${JSON.stringify(exportResp, null, 4)}`)

    /** ------------------------------- 获取导出用户数据 json ------------------------------------------------- */
    await sleep(1000)
    const userJsonResp = await fetch(`${httpServerURL}/static/user.json`)
    console.log(`用户数据 json: ${await userJsonResp.text()}`)

    await sleep(1000)
    console.log('测试结束')
}

process.on('SIGTERM', () => {
    childprocess1.kill(0)
    childprocess2.kill(0)
    process.exit(0)
})

async function main() {
    try {
        const { port, mqtt: { port: mqttBrokerPort } } = config;
        await cleanupPorts([port, mqttBrokerPort])
        const { childprocess1, childprocess2 } = await startServer()
        sleep(2000)
        await test()
        await sleep(1000)
        childprocess1.kill(0)
        childprocess2.kill(0)
        process.exit(0)
    } catch (error) {
        console.error(error)
    }
}

main()
